﻿using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MikeKappel.Com.Uploader
{
    internal static class Core
    {
        internal enum FormErrorTypes
        {
            Oversize,
            Unsupported,
            Cancelled
        }
        internal const String ImageKey = "id";
        internal const String CommandKey = "q";
        internal const String PageHtml = "<html>\n\t<head>\n\t\t{0}\n\t</head>\n\t<body>\n\t\t{1}\n\t</body>\n</html>";
        internal const String CssFileHtml = "<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />";
        internal const String ScriptHtml = "<script type=\"text/javascript\"/>{0}</script>";
        internal const String ChangeImageHtml = "<a href=\"{0}\" class=\"change\">{1}</a>";
        internal const String ImageHtml = "<img src=\"{0}\" class=\"upload\" />";
        internal const String FormHtml = "\n\t\t<form class=\"upload\" name=\"upload\" method=\"post\" enctype=\"multipart/form-data\" action=\"{0}\" >\n\t\t\t<input type=\"file\" class=\"upload\" name=\"fileToUpload\" value=\"\" onchange=\"document.getElementById('btnCancel').style.display = '';this.style.display = 'none';document.forms['upload'].submit();return parent.UploadStared('{1}');\" /><input type=\"button\" name=\"Uancel\" id=\"btnCancel\" onclick=\"return parent.UploadCancel('{1}');\" value=\"Cancel\" style=\"display:none;\" />\n\t\t</form>";
        internal const String BasePage = "/Images.aspx";

        internal static String GetUrlOfImage(Guid id)
        {
            return String.Format("{0}?{1}={2}&{3}=original", BasePage, ImageKey, id, CommandKey);
        }
        internal static String GetUrlOfThumbnail(Guid id)
        {
            return String.Format("{0}?{1}={2}&{3}=thumbnail", BasePage, ImageKey, id, CommandKey);
        }
        internal static String GetUrlOfProgress(Guid id)
        {
            return String.Format("{0}?{1}={2}&{3}=progress", BasePage, ImageKey, id, CommandKey);
        }
        internal static String GetUrlOfCancel(Guid id)
        {
            return String.Format("{0}?{1}={2}&{3}=cancel", BasePage, ImageKey, id, CommandKey);
        }
        internal static String GetUrlOfForm(Guid id)
        {
            return String.Format("{0}?{1}={2}&{3}=form", BasePage, ImageKey, id, CommandKey);
        }
        internal static String GetUrlOfSubmission(Guid id)
        {
            return String.Format("{0}?{1}={2}", BasePage, ImageKey, id);
        }
        internal static UploaderInfo GetUploader(Guid id)
        {
            return (UploaderInfo)HttpContext.Current.Cache[id.ToString()];
        }
        internal static void SetUploader(UploaderInfo uploader)
        {
            Cache(uploader.ID.ToString(), uploader);
        }
        internal static String GetHtmlCss(UploaderInfo uploader)
        {
            return (String.IsNullOrEmpty(uploader.CssUrlInner)) ? "" : String.Format(Core.CssFileHtml, uploader.CssUrlInner);
        
        }
        internal static String GetHtmlPageUploadCompleate(UploaderInfo uploader)
        {
            return String.Format(PageHtml, GetHtmlCss(uploader), String.Format(ImageHtml, GetUrlOfThumbnail(uploader.ID)) + String.Format(ChangeImageHtml, GetUrlOfForm(uploader.ID), uploader.TextForImageChange));
        }
        internal static String GetHtmlPageUploadFormError(UploaderInfo upload, FormErrorTypes errorType, String info)
        {
            String message = "Error";
            if (errorType == FormErrorTypes.Oversize)
                message = String.Format(upload.TextForOversize, info);
            else if (errorType == FormErrorTypes.Unsupported)
                message = String.Format(upload.TextForUnsupported, info);
            else if (errorType == FormErrorTypes.Cancelled)
                message = upload.TextForCancelled;

            return Core.GetHtmlPageUploadForm(upload, String.Format("alert('{0}');", message));
        }
        internal static String GetHtmlPageUploadForm(UploaderInfo upload)
        {
            return GetHtmlPageUploadForm(upload, String.Format("parent.FormLoaded('{0}');", upload.Name));
        }
        internal static String GetHtmlPageUploadForm(UploaderInfo upload, String script)
        {
            return String.Format(PageHtml, ((String.IsNullOrEmpty(script)) ? "" : String.Format(ScriptHtml, script)) + GetHtmlCss(upload), String.Format(FormHtml, Core.GetUrlOfSubmission(upload.ID),upload.Name));
        }
        internal static void GenerateThumbnail(HttpResponse Response, UploaderInfo upload)
        {
            Response.Buffer = true;
            Response.Clear();
            Response.ContentType = upload.Mime;
            System.Drawing.Image image = System.Drawing.Image.FromStream(new System.IO.MemoryStream(upload.Content));
            image.GetThumbnailImage(upload.Width, upload.Height, null, IntPtr.Zero).Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
            image.Dispose();
            Response.Flush();
            Response.End();
        }
        internal static void Download(HttpResponse Response, UploaderInfo upload)
        {
            Response.Buffer = true;
            Response.Clear();
            Response.ContentType = upload.Mime;
            Response.BinaryWrite(upload.Content);
            Response.Buffer = false;
            Response.Flush();
            Response.End();
        }
        internal static String SaveImageToMemory(HttpRequest Request, HttpResponse Response, HttpWorkerRequest worker, UploaderInfo uploader)
        {
            uploader.Progress = 0;
            Int64 fileSize = worker.GetTotalEntityBodyLength() + 1;
            Byte[] postedData = new Byte[fileSize];
            Int32 read = 0;
            Int32 ii = worker.GetPreloadedEntityBodyLength();
            Byte[] buffer = new Byte[1024];

            System.Threading.Thread.Sleep(10);

            if (worker.GetPreloadedEntityBody() != null)
                Array.Copy(worker.GetPreloadedEntityBody(), 0, postedData, 0, ii);

            while ((read = worker.ReadEntityBody(buffer, buffer.Length)) > 0)
            {
                if (System.Threading.Interlocked.Add(ref ii, read) <= postedData.Length)
                {
                    Array.Copy(buffer, 0, postedData, ii - read, read);
                    Int32 percent = Convert.ToInt32(Math.Ceiling((Decimal)ii / (Decimal)fileSize * (Decimal)100));
                    if (uploader.Progress != percent)
                    {
                        uploader.Progress = percent;
                        System.Threading.Thread.Sleep(10);
                        if (uploader == null || !uploader.Progress.HasValue)
                            break;

                        if (String.IsNullOrEmpty(uploader.Mime))
                        {
                            uploader.Mime = Helper.GetUploadContentType(postedData);
                            if (!String.IsNullOrEmpty(uploader.Mime) && !IsContentTypeAllowed(uploader.MimesExcepted, uploader.Mime))
                            {
                                uploader.Progress = null;
                                return GetHtmlPageUploadFormError(uploader, FormErrorTypes.Unsupported, uploader.Mime);
                            }
                        }

                    }
                }
            }

            if (!uploader.Progress.HasValue)
                Response.End();

            if (String.IsNullOrEmpty(uploader.Mime))
            {
                uploader.Mime = Helper.GetUploadContentType(postedData);
                if (!String.IsNullOrEmpty(uploader.Mime) && !IsContentTypeAllowed(uploader.MimesExcepted, uploader.Mime))
                {
                    return GetHtmlPageUploadFormError(uploader, FormErrorTypes.Unsupported, uploader.Mime);
                }
            }
            Int32 fileStart = Helper.FirstIndexOf(postedData, new Byte[] { 13, 10, 13, 10 }) + 4;
            Byte[] EndOfUpload = (new System.Text.ASCIIEncoding()).GetBytes("\r\n--------------------".ToCharArray());
            Int32 fileBoundary = Helper.FirstIndexOf(postedData, EndOfUpload);
            uploader.Progress = 100;
            uploader.Content = new Byte[fileBoundary];
            Array.Copy(postedData, fileStart, uploader.Content, 0, fileBoundary - fileStart);
            return Core.GetHtmlPageUploadCompleate(uploader);
        }
        internal static void Dispose(Guid id)
        {
            Cache(id.ToString(), null);
        }
        private static Boolean IsContentTypeAllowed(String[] allowedContentMimes, String contentMimes)
        {
            return (allowedContentMimes == null || allowedContentMimes.Length == 0 || Array.IndexOf(allowedContentMimes, contentMimes) >= 0);
        }
        private static void Cache(String key, Object value)
        {
            if (HttpContext.Current.Cache[key] == null && value != null)
                HttpContext.Current.Cache.Add(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(1, 0, 0), System.Web.Caching.CacheItemPriority.Default, null);
            else if (value != null)
                HttpContext.Current.Cache[key] = value;
            else
                HttpContext.Current.Cache.Remove(key);
        }
    }
}
